#!/usr/bin/env python2
#-*- coding: utf-8 -*-

"初始化数据库"

import traceback
import sys
import os
import argparse
import textwrap
import hashlib
import uuid
import random
import datetime


from Ump import utils
from Ump import defs
from Ump.common.config_base import ConfigManager

from Ump.objs.session_wrapper import _sw
from Ump.objs.db import models
from Ump.objs.db import config as db_config
from Ump.objs.db.session import init_db_session
from Ump.objs.sysconfigforump.manager import SysconfigForUMPManager
from Ump.objs.schedule.manager import ScheduleManager
from Ump.schedule import init_sysconfig_for_ump



class InitDbShell(object):

    def __init__(self):
        self.install_path = utils.install_path
        self.db_cfg_path = defs.DB_CFG_PATH

    def get_parser(self):
        parser = argparse.ArgumentParser(
            prog ='InitUmpDatabase',
            formatter_class=argparse.RawDescriptionHelpFormatter,
            description=textwrap.dedent("""
            +------------------------------------------------------------------+
            |    Initialization Ump database                                   |
            |    Automatically create the database configuration file          |
            |    %s                          |
            |                                                                  |
            |    ump-initdb sqlite -n /var/mydatabase.db                       |
            |                                                                  |
            |    ump-initdb mysql -u root -p root -d ump                       |
            |                                                                  |
            +------------------------------------------------------------------+
            """ % defs.DB_CFG_PATH),
#            add_help=False,
        )

        subparsers = parser.add_subparsers(dest='subcommand',metavar='<subcommand>')

        sqlite_parser = subparsers.add_parser('sqlite', help='use sqlite database')
        sqlite_parser.add_argument('-n', '--name',
            metavar='<name>',
            required=True,
            help='Select the sqlite database location.')

        mysql_parser = subparsers.add_parser('mysql', help='use mysql database')
        mysql_parser.add_argument('-u', '--user',
            metavar='<user>',
            required=True,
            help='mysql user name')
        mysql_parser.add_argument('-p', '--password',
            nargs="?",
            metavar='<password>',
            help='mysql password')
        mysql_parser.add_argument('-d', '--database',
            metavar='<database>',
            required=True,
            help='mysql database')
        mysql_parser.add_argument('--host',
            metavar='<host>',
            default='127.0.0.1',
            help='mysql host')
        mysql_parser.add_argument('--port', type=int,
            metavar='<port>',
            default=3306,
            help='mysql port')

        mysql_parser.add_argument('-f', '--force',  action='store_true', default=False, help='developer method')

        return parser

    
    def get_args(self):
        argv = sys.argv[1:]
        parser = self.get_parser()
        if argv == []:
            parser.print_help()

        args = parser.parse_args(argv)
        return args

    def main(self, args=None):
        if args is None:
            args = self.get_args()
    
        db_configm = ConfigManager(defs.DB_CFG_PATH)

        password = args.password if args.password else ''
        section = args.subcommand

        db_cfg_kw = {'server': section}
        if args.subcommand == 'mysql' or args.server == 'mysql':
            db_cfg_kw['user'] = args.user
            db_cfg_kw['password'] = password
            db_cfg_kw['database'] = args.database
            db_cfg_kw['host'] = args.host
            db_cfg_kw['port'] = args.port
            db_cfg_kw['server'] = 'mysql'

        sql_uri = db_config._association_uri(**db_cfg_kw)

        try:
            register_models(sql_uri, is_force=args.force)
            db_configm.set_option(db_cfg_kw['server'], **db_cfg_kw)
            print 'Writing file: %s' % self.db_cfg_path
        except OSError:
            print 'I/O error maybe permission denied!'
        except Exception,e:
            traceback.print_exc()


def db_create(model, values):
    return model(values).save()


def init_role(role_name):
    role = _sw.get_one(models.Role, id_or_spec={'name': role_name})
    if not role:
        values = {
            'name': role_name,
        }
        role = models.Role(values).save()
    return role


def init_permission(tenancyRole):
    resources = [
        ("概览", "DASHBOARD"),
        ("保护域", "PROTECTION_DOMAIN"),
        ("节点", "HOST"),
        ("磁盘", "DISK"),
        ("资源池", "POOL"),
        ("卷",  "VOLUME"),
        ("卷组", "CGSNAPSHOT"),
        ("卷快照", "SNAPSHOT"),
        ("卷组快照", "SNAPGROUP"),
        ("自动快照策略", "AUTOSNAPSHOT"),
        ("访问策略",     "ACCESSPOLICY"),
        ("QoS",         "QoS"),
        ("操作日志", "EVENT"),
        ("报警管理", "ALERT"),
        ("注册管理", "LICENSE"),
        ("升级",     "UPGRADE"),
        ("系统设置", "SETTINGS"),
        ("用户",    "USER"),
        ("远程复制", "REMOTECOPY"),
    ]

    for resource in resources:
        resource_type = resource[1]
        values = {
            'resource_type': resource_type,
            'description': resource[0]
        }
        permission = _sw.get_one(models.Permission, id_or_spec={'resource_type': resource_type})
        if not permission:
            permission = db_create(models.Permission, values)

    tenancyResource = ["DASHBOARD", "VOLUME", "SNAPSHOT",  "ISOLATION", "QoS", "POOL"]
    tenancy_permissions = []
    for resource_type in tenancyResource:
        permission = _sw.get_one(models.Permission, id_or_spec={'resource_type': resource_type})
        if permission:
            tenancy_permissions.append(permission)

    values = {
        "permissions": tenancy_permissions,
    }
    tenancyRole.update(values)

def init_alembic_version():
    #MIGRATIONS VERSION NEWEST FILE
    cmd = 'basename $(ls %s/migrations/versions/*.py -t|head -1)' % (defs.UMP_PATH) 
    version_file = os.popen(cmd).read()
    version = version_file.strip().split('_')[0]

    alembic_version = models.AlembicVersion.query.first()
    if not alembic_version:
        alembic_version = models.AlembicVersion({'version_num':version}).save()
    return alembic_version


def register_models(sql_uri, is_force=False):
    # TODO

    from Ump import create_app

    app, db = create_app('default', SQLALCHEMY_DATABASE_URI=sql_uri)
    init_db_session(db)
    with app.app_context():
        # database can only be initialized once!
        if (not is_force) and models.User.__table__.exists(db.session.bind) and models.User.query.all():
            sys.stderr.write('ERR: Database has already been initialized!\n')
            sys.exit(1)

        db.create_all()

        alembic_version = init_alembic_version()

        administratorRole = init_role('administrator')
        tenancyRole = init_role('tenancy')
        init_permission(tenancyRole)
        ScheduleManager().init_schedule()

        init_sysconfig_for_ump.main()
        ScheduleManager.init_backup_job_schedule()

        # user 'admin'
        admin_user = _sw.get_one(models.User, id_or_spec={'name': 'admin'})
        if not admin_user:
            values = {
                'name': 'admin',
                'password': hashlib.md5('admin').hexdigest(),
                'fullname': 'first user',
                'roles': [administratorRole],
                'role': 1,
                'telephone': '',
                'description':'super user',
                'extra':'x'
            }
            admin = db_create(models.User, values)

        # cluster 1
        cluster = _sw.get_one(model=models.Cluster, id_or_spec=1)
        if not cluster:
            clusterName = str(uuid.uuid4()).replace('-', '')
            values = {'name': clusterName}
            db_create(models.Cluster, values)

    print 'Successfully initialization Ump database'


def main():
    InitDbShell().main()


if __name__ == "__main__":
    try:
        InitDbShell().main()
    except Exception, e:
        print >> sys.stderr, e
        sys.exit(1)
